package com.lifeverse.entity;

import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 资源分配记录实体类
 * 记录资源的分配和使用情况
 */
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "resource_allocations", indexes = {
    @Index(name = "idx_allocation_resource", columnList = "resource_id"),
    @Index(name = "idx_allocation_user", columnList = "allocated_to_id"),
    @Index(name = "idx_allocation_decision", columnList = "decision_id"),
    @Index(name = "idx_allocation_time", columnList = "allocated_at"),
    @Index(name = "idx_allocation_status", columnList = "allocation_status")
})
public class ResourceAllocation extends BaseEntity {
    
    /**
     * 分配的资源
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "resource_id", nullable = false)
    private Resource resource;
    
    /**
     * 资源分配给的生命体
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "allocated_to_id", nullable = false)
    private LifeEntity allocatedTo;
    
    /**
     * 分配决策
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "decision_id")
    private Decision decision;
    
    /**
     * 分配数量
     */
    @Column(name = "allocated_amount", nullable = false, precision = 15, scale = 4)
    private BigDecimal allocatedAmount;
    
    /**
     * 实际使用数量
     */
    @Column(name = "used_amount", precision = 15, scale = 4)
    private BigDecimal usedAmount = BigDecimal.ZERO;
    
    /**
     * 分配状态
     */
    @Column(name = "allocation_status", nullable = false, length = 20)
    private String allocationStatus = "ACTIVE";
    
    /**
     * 分配时间
     */
    @Column(name = "allocated_at", nullable = false)
    private LocalDateTime allocatedAt;
    
    /**
     * 开始使用时间
     */
    @Column(name = "started_at")
    private LocalDateTime startedAt;
    
    /**
     * 结束时间
     */
    @Column(name = "ended_at")
    private LocalDateTime endedAt;
    
    /**
     * 计划释放时间
     */
    @Column(name = "planned_release_at")
    private LocalDateTime plannedReleaseAt;
    
    /**
     * 实际释放时间
     */
    @Column(name = "actual_release_at")
    private LocalDateTime actualReleaseAt;
    
    /**
     * 分配原因
     */
    @Column(name = "allocation_reason", length = 500)
    private String allocationReason;
    
    /**
     * 分配优先级
     */
    @Column(name = "priority", nullable = false)
    private Integer priority = 5;
    
    /**
     * 分配成本
     */
    @Column(name = "allocation_cost", precision = 12, scale = 4)
    private BigDecimal allocationCost;
    
    /**
     * 使用效率评分
     */
    @Column(name = "efficiency_score", precision = 5, scale = 2)
    private BigDecimal efficiencyScore;
    
    /**
     * 分配标签（JSON格式）
     */
    @Column(name = "tags", length = 500)
    private String tags;
    
    /**
     * 分配属性（JSON格式）
     */
    @Column(name = "attributes", columnDefinition = "TEXT")
    private String attributes;
    
    /**
     * 使用统计（JSON格式）
     */
    @Column(name = "usage_statistics", columnDefinition = "TEXT")
    private String usageStatistics;
    
    /**
     * 性能指标（JSON格式）
     */
    @Column(name = "performance_metrics", columnDefinition = "TEXT")
    private String performanceMetrics;
    
    @PrePersist
    protected void onCreate() {
        super.onCreate();
        if (allocatedAt == null) {
            allocatedAt = LocalDateTime.now();
        }
    }
    
    /**
     * 开始使用资源
     */
    public void startUsing() {
        this.startedAt = LocalDateTime.now();
        this.allocationStatus = "IN_USE";
    }
    
    /**
     * 结束使用资源
     */
    public void endUsing() {
        this.endedAt = LocalDateTime.now();
        this.actualReleaseAt = LocalDateTime.now();
        this.allocationStatus = "COMPLETED";
    }
    
    /**
     * 取消分配
     */
    public void cancel(String reason) {
        this.endedAt = LocalDateTime.now();
        this.actualReleaseAt = LocalDateTime.now();
        this.allocationStatus = "CANCELLED";
        this.allocationReason = (this.allocationReason != null ? this.allocationReason + " | " : "") + 
                               "取消原因: " + reason;
    }
    
    /**
     * 计算使用率
     */
    public BigDecimal getUsageRate() {
        if (allocatedAmount == null || allocatedAmount.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        if (usedAmount == null) {
            return BigDecimal.ZERO;
        }
        return usedAmount.divide(allocatedAmount, 4, java.math.RoundingMode.HALF_UP);
    }
    
    /**
     * 计算使用时长（分钟）
     */
    public long getUsageDurationMinutes() {
        if (startedAt == null) {
            return 0;
        }
        
        LocalDateTime endTime = endedAt != null ? endedAt : LocalDateTime.now();
        return java.time.Duration.between(startedAt, endTime).toMinutes();
    }
    
    /**
     * 判断是否已过期
     */
    public boolean isExpired() {
        if (plannedReleaseAt == null) {
            return false;
        }
        return LocalDateTime.now().isAfter(plannedReleaseAt) && actualReleaseAt == null;
    }
    
    /**
     * 判断是否活跃
     */
    public boolean isActive() {
        return "ACTIVE".equals(allocationStatus) || "IN_USE".equals(allocationStatus);
    }
    
    /**
     * 判断是否已完成
     */
    public boolean isCompleted() {
        return "COMPLETED".equals(allocationStatus) || "CANCELLED".equals(allocationStatus);
    }
    
    /**
     * 更新使用量
     */
    public void updateUsedAmount(BigDecimal amount) {
        if (amount != null && amount.compareTo(BigDecimal.ZERO) >= 0 && 
            amount.compareTo(allocatedAmount) <= 0) {
            this.usedAmount = amount;
        }
    }
    
    /**
     * 计算实际成本
     */
    public BigDecimal calculateActualCost() {
        if (resource == null || resource.getUnitCost() == null || usedAmount == null) {
            return BigDecimal.ZERO;
        }
        return resource.getUnitCost().multiply(usedAmount);
    }
    
    /**
     * 计算成本效率
     */
    public BigDecimal calculateCostEfficiency() {
        BigDecimal actualCost = calculateActualCost();
        if (allocationCost == null || allocationCost.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        if (actualCost.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.valueOf(100);
        }
        return allocationCost.subtract(actualCost).divide(allocationCost, 4, java.math.RoundingMode.HALF_UP)
               .multiply(BigDecimal.valueOf(100));
    }
}